1 /* 2 * Collie - An asynchronous event-driven network framework using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: putao's Dlang team 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module collie.codec.http.server.requesthandler; 12 import kiss.logger; 13 import collie.codec.http.httpmessage; 14 import collie.codec.http.server.responsehandler; 15 import collie.codec.http.errocode; 16 import collie.codec.http.codec.wsframe; 17 import collie.codec.http.headers; 18 import collie.codec.http.httptansaction; 19 import collie.codec.http.server.responsebuilder; 20 import collie.codec.http.codec.httpcodec; 21 import collie.utils.string; 22 import kiss.event; 23 24 abstract class RequestHandler 25 { 26 void setResponseHandler(ResponseHandler handler) nothrow 27 { 28 _downstream = handler; 29 } 30 31 @property ResponseHandler responseHandler() 32 { 33 return _downstream; 34 } 35 36 /** 37 * Invoked when we have successfully fetched headers from client. This will 38 * always be the first callback invoked on your handler. 39 */ 40 void onRequest(HttpMessage headers) nothrow 41 { 42 } 43 44 /** 45 deprecated("Incorrect spelling. Using onRequest instead.") 46 */ 47 void onResquest(HttpMessage headers) nothrow 48 { 49 onRequest(headers); 50 } 51 52 /** 53 * Invoked when we get part of body for the request. 54 */ 55 void onBody(const ubyte[] data) nothrow; 56 57 /** 58 * Invoked when we finish receiving the body. 59 */ 60 void onEOM() nothrow; 61 62 /** 63 * Invoked when request processing has been completed and nothing more 64 * needs to be done. This may be a good place to log some stats and 65 * clean up resources. This is distinct from onEOM() because it is 66 * invoked after the response is fully sent. Once this callback has been 67 * received, `downstream_` should be considered invalid. 68 */ 69 void requestComplete() nothrow; 70 71 /** 72 * Request failed. Maybe because of read/write error on socket or client 73 * not being able to send request in time. 74 * 75 * NOTE: Can be invoked at any time (except for before onRequest). 76 * 77 * No more callbacks will be invoked after this. You should clean up after 78 * yourself. 79 */ 80 void onError(HTTPErrorCode code) nothrow; 81 82 void onFrame(ref WSFrame frame) nothrow 83 { 84 } 85 86 bool onUpgtade(CodecProtocol protocol, HttpMessage msg) nothrow 87 { 88 return false; 89 } 90 91 protected: 92 ResponseHandler _downstream; 93 } 94 95 final class RequestHandlerAdaptor : ResponseHandler, HTTPTransactionHandler 96 { 97 this(RequestHandler handler) 98 { 99 super(handler); 100 } 101 102 override void setTransaction(HTTPTransaction txn) 103 { 104 _txn = txn; 105 _upstream.setResponseHandler(this); 106 } 107 108 override void detachTransaction() 109 { 110 _txn = null; 111 if (!_erro) 112 { 113 _upstream.requestComplete(); 114 } 115 } 116 117 override void onHeadersComplete(HttpMessage msg) 118 { 119 // logDebug("onHeadersComplete , erro is : ", _erro , " _upstream is ", cast(void *)_upstream); 120 if (msg.getHeaders.exists(HTTPHeaderCode.EXPECT)) 121 { 122 logDebug("has header EXPECT--------"); 123 string str = msg.getHeaders.getSingleOrEmpty(HTTPHeaderCode.EXPECT); 124 if (!isSameIngnoreLowUp(str, "100-continue")) 125 { 126 scope HttpMessage headers = new HttpMessage(); 127 headers.constructDirectResponse(1, 1, 417, "Expectation Failed"); 128 headers.wantsKeepAlive(false); 129 _txn.sendHeadersWithEOM(headers); 130 return; 131 } 132 else 133 { 134 scope HttpMessage headers = new HttpMessage(); 135 headers.constructDirectResponse(1, 1, 100, "Continue"); 136 _txn.sendHeaders(headers); 137 } 138 } 139 if (!_erro) 140 _upstream.onResquest(msg); 141 } 142 143 override void onBody(const ubyte[] chain) 144 { 145 _upstream.onBody(chain); 146 } 147 148 override void onChunkHeader(size_t lenght) 149 { 150 } 151 152 override void onChunkComplete() 153 { 154 } 155 156 override void onEOM() 157 { 158 if (!_erro) 159 _upstream.onEOM(); 160 } 161 162 override void onError(HTTPErrorCode erromsg) 163 { 164 if (_erro) 165 return; 166 version(CollieDebugMode) { 167 import std.conv; 168 warning(to!string(erromsg)); 169 } 170 _erro = true; 171 _upstream.onError(erromsg); 172 } 173 174 override void onWsFrame(ref WSFrame wsf) 175 { 176 _upstream.onFrame(wsf); 177 } 178 179 override void onEgressPaused() 180 { 181 } 182 183 override void onEgressResumed() 184 { 185 } 186 187 override void sendHeadersWithEOM(HttpMessage msg) 188 { 189 if (_txn) 190 _txn.sendHeadersWithEOM(msg); 191 } 192 193 override void sendHeaders(HttpMessage msg) 194 { 195 _responseStarted = true; 196 if (_txn) 197 _txn.sendHeaders(msg); 198 } 199 200 override void sendChunkHeader(size_t len) 201 { 202 if (_txn) 203 _txn.sendChunkHeader(len); 204 } 205 206 override void sendBody(in ubyte[] data, bool iseom = false) 207 { 208 if (_txn) 209 _txn.sendBody(data, iseom); 210 if (iseom) 211 _responseStarted = false; 212 } 213 214 override void sendChunkTerminator() 215 { 216 if (_txn) 217 _txn.sendChunkTerminator(); 218 } 219 220 override void sendEOM() 221 { 222 if (_txn) 223 _txn.sendEOM(); 224 _responseStarted = false; 225 } 226 227 override void sendTimeOut() 228 { 229 if (_txn) 230 _txn.sendTimeOut(); 231 } 232 233 override void socketWrite(StreamWriteBuffer buffer) 234 { 235 if (_txn) 236 _txn.socketWrite(buffer); 237 } 238 239 override void sendWsData(OpCode code, ubyte[] data) 240 { 241 if (_txn) 242 _txn.sendWsData(code, data); 243 } 244 245 override bool onUpgtade(CodecProtocol protocol, HttpMessage msg) 246 { 247 return _upstream.onUpgtade(protocol, msg); 248 } 249 250 private: 251 HTTPTransaction _txn; 252 bool _erro = false; 253 bool _responseStarted = false; 254 }